interface FieldMapping {
    [key: string]: string;
}

export default class CDOProxy {
    private cdoCode: any;
    private _cdo: any;
    private fieldMapping: FieldMapping;
    private _emit: any;
    private contentWindow: any;
    constructor(cdCode: any, fieldMapping: FieldMapping, contentWindow: any,emit:any) {
        this.cdoCode = cdCode;
        this._emit = emit;
        this._cdo = globalThis.CDO ? globalThis.CDO : null;
        this.fieldMapping = {
            id: 'ID',
            Id: 'ID',
            creator: 'Creator',
            lastmodifier: 'LastModifier',
            createdtime: 'CreatedTime',
            lastmodifytime: 'LastModifyTime',
            lastModifiedTime: 'LastModifyTime',
            LastModifiedTime: 'LastModifyTime',
            CreatedBy: 'Creator',
            LastModifiedBy: 'LastModifier',

            ...fieldMapping
        };
        this.contentWindow = contentWindow;
    }
    callback(operationId, id?: string, action?: string) {
        if (!operationId) return
        this.contentWindow.postMessage({
            operationId: operationId,
            action: action || 'refresh',
            id
        }, '*');
    }
    parseParams(params: any) {
        params = params;
        let recordId = params.recordId;
        const fieldIdMappingName: any = {}
        if (params.fieldMap) {
            for (let i in params.fieldMap) {
                fieldIdMappingName[i] = params.fieldMap[i]
            }
        }
        if (params.fields) {
            params.fields.forEach((field: any) => {
                if (field.id && field.dbFieldName) {
                    fieldIdMappingName[field.id] = field.dbFieldName;
                }

            })
        }
        const result: any = {};
        if (params && typeof params === 'object') {
            let recordsFields = params.records.fields?.fields || params.records.fields;
            for (const i in recordsFields) {
                const mappedField =
                    this.fieldMapping[fieldIdMappingName[i]] ||
                    this.fieldMapping[i] ||
                    i;
                if (mappedField) {
                    result[mappedField] = recordsFields[i];
                }
            }
        }

        if (!this.fieldMapping.id) {
            this.fieldMapping.id = 'ID'
        }
        // 将 fieldMapping 的所有字段合并为一个对象，并赋默认值
        // const defaultFields = Object.values(this.fieldMapping).reduce((acc: any, fieldName: string) => {
        //     acc[fieldName] = fieldName === 'ID' ? globalThis.Funcs.Guid() : null;
        //     return acc;
        // }, {});
        const defaultFields = {
            ID: recordId || globalThis.Funcs.Guid()
        }
        // 解析 ISO UTC/含时区 的时间字符串，返回有效 Date
        const parseISOStringToDate = (timeString: string): Date | null => {
            if (!timeString) return null;
            if (typeof timeString !== 'string') return null;
            return new Date(timeString.replace(/T/ig, ' ').replace(/Z/ig, ''));
            // 形如: 2025-07-30T11:21:15.576Z 或 2025-07-30 11:21:15Z 或 带偏移 2025-07-30T11:21:15.576+08:00
            const isoRegex = /^(\d{4})-(\d{2})-(\d{2})[ T](\d{2}):(\d{2}):(\d{2})(?:\.(\d{1,3}))?(Z|[+-]\d{2}:?\d{2})?$/;
            const match = timeString.match(isoRegex);
            if (!match) {
                // 尝试使用原生解析作为兜底
                const n = new Date(timeString);
                return isNaN(n.getTime()) ? null : n;
            }
            const [_, y, mo, d, h, mi, s, msRaw, tz] = match;
            const year = parseInt(y, 10);
            const month = parseInt(mo, 10) - 1;
            const day = parseInt(d, 10);
            const hour = parseInt(h, 10);
            const minute = parseInt(mi, 10);
            const second = parseInt(s, 10);
            const milli = msRaw ? parseInt(msRaw.padEnd(3, '0').slice(0, 3), 10) : 0;

            // 无时区信息：按本地时间直接构造，不做额外偏移
            if (!tz) {
                return new Date(year, month, day, hour, minute, second, milli);
            }

            // Z 结尾：已是 UTC
            if (tz === 'Z') {
                const utcMs = Date.UTC(year, month, day, hour, minute, second, milli);
                return new Date(utcMs);
            }

            // 显式偏移：根据偏移换算为 UTC 毫秒
            let offsetMinutes = 0; // 相对 UTC 的偏移分钟数
            const tzMatch = tz.match(/^([+-])(\d{2}):?(\d{2})$/);
            if (tzMatch) {
                const sign = tzMatch[1] === '-' ? -1 : 1;
                const tzh = parseInt(tzMatch[2], 10);
                const tzm = parseInt(tzMatch[3], 10);
                offsetMinutes = sign * (tzh * 60 + tzm);
            }
            const utcMs = Date.UTC(year, month, day, hour, minute, second, milli) - offsetMinutes * 60 * 1000;
            return new Date(utcMs);
        };
        // 处理UTC时间转换为本地时间（若需要字符串形式，可使用统一格式化）
        // 已统一用 parsedDate + Funcs.FormatDateTime 输出

        const parsedDate = parseISOStringToDate(result.LastModifyTime||result.lastModifiedTime) || new Date();

        // 手动格式化毫秒部分，因为某些环境可能不支持 .fff 格式
        const formatWithMilliseconds = (date: Date) => {
            const year = date.getFullYear();
            const month = String(date.getMonth() + 1).padStart(2, '0');
            const day = String(date.getDate()).padStart(2, '0');
            const hours = String(date.getHours()).padStart(2, '0');
            const minutes = String(date.getMinutes()).padStart(2, '0');
            const seconds = String(date.getSeconds()).padStart(2, '0');
            const milliseconds = String(date.getMilliseconds()).padStart(3, '0');

            return `${year}-${month}-${day} ${hours}:${minutes}:${seconds}.${milliseconds}`;
        };

        return {
            ...defaultFields, ...result, LastModifyTime: {
                //@ts-ignore
                Value: Funcs.FormatDateTime(parsedDate, 'yyyy-MM-dd HH:mm:ss'),
                Data: result.LastModifyTime ? formatWithMilliseconds(parsedDate) : null,
                Format: "yyyy-MM-dd HH:mm:ss.fff"
            }
        };
    }
    mappingParamsToLocalvars(params: any) {
        //@ts-ignore
        if (window?.LocalVars) {
            //@ts-ignore
            window.LocalVars.Teable = {
                records: this.parseParams({
                    fields: params.columns,

                    fieldMap: params.fieldMap,
                    records: {
                        fields: params.fields
                    }
                })
            }
        }
    }

    update(params: any) {
        //@ts-ignore
        if (window.CDO && this.cdoCode) {

            const mappedField = this.parseParams(JSON.parse(params).params);
            let emitOpt = {
                data:mappedField,
                cancel:false
            }
            this._emit('beforeUpdate', emitOpt);
            if(emitOpt.cancel){
                return;
            }
            this._cdo.Update_Async(this.cdoCode, mappedField).then((res: any) => {
                this.callback(JSON.parse(params).operationId, res?.ID);
            }).catch((error: any) => {
                //@ts-ignore
                Funcs.Notify('提示', error, 'warning')
                this.callback(JSON.parse(params).operationId, '', 'cancel');
            });
        } else {
            this.callback(JSON.parse(params).operationId);
        }
    }
    delete(params: any) {
        /**
         *
[{"Order":0,"ParameterName":"CDOID","ParameterValue":"CDO_DO_DEP_ProjectBug"},{"Order":1,"ParameterName":"ID","ParameterValue":"315ffbeb-2f12-78a0-885e-d8ce8c9be672"}]
         */
        //@ts-ignore
        if (window.CDO && this.cdoCode) {
            const ids: any = JSON.parse(params).params?.selectedData?.map(item => item.id) || [JSON.parse(params).params?.recordId];
            let deleteProxy: any = null
            if (ids.length > 1) {
                deleteProxy = this._cdo.BatchDelete_Async(this.cdoCode, ids)
            } else {
                deleteProxy = this._cdo.Delete_Async(this.cdoCode, ids[0])
            }
            let emitOpt = {
                data:ids,
                cancel:false
            }
            this._emit('beforeDelete', emitOpt);
            if(emitOpt.cancel){
                return;
            }
            deleteProxy.then(() => {
                this.callback(JSON.parse(params).operationId);
            }).catch((error: any) => {
                //@ts-ignore
                Funcs.Notify('提示', error, 'warning')
                this.callback(JSON.parse(params).operationId, '', 'cancel');
            });
        } else {
            this.callback(JSON.parse(params).operationId);
        }
    }
    create(params) {
        //@ts-ignore
        if (window.CDO && this.cdoCode) {
            const mappedField = this.parseParams(JSON.parse(params).params);
            let emitOpt = {
                data:mappedField,
                cancel:false
            }
            this._emit('beforeCreate', emitOpt);
            if(emitOpt.cancel){
                return;
            }
            this._cdo.Create_Async(this.cdoCode, JSON.stringify(mappedField)).then((res) => {
                const recid: any = res?.ID;
                this.callback(JSON.parse(params).operationId, recid);
            }).catch((error: any) => {
                //@ts-ignore
                Funcs.Notify('提示', error, 'warning')
                this.callback(JSON.parse(params).operationId, '', 'cancel');
                //this.callback(JSON.parse(params).operationId);
            });
        } else {
            this.callback(JSON.parse(params).operationId);
        }
    }




}
